package com.desire.test;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.MappedByteBuffer;
import java.nio.channels.FileChannel;
import java.nio.file.*;

    /*

    FileVisitor 接口主要用作 Files 类中的 walkFileTree（walkFileTree方法用以访问目录中所有的子孙成员）方法中。
    接口的主要方法：
        postVisitDirectory(T dir, IOException exc) 在一个目录被处理后
        preVisitDirectory(T dir, BasicFileAttributes attrs) 在一个目录被处理前
        visitFile(T file, BasicFileAttributes attrs) 在遇到一个文件或目录时
        visitFileFailed(T file, IOException exc) 在试图访问文件或目录，发生错误时。例如：没有权限打开目录；
    3.针对以上的情况都可以指定接下来执行的步骤：
        FileVisitResult 枚举类：
            CONTINUE 　　继续访问一下一个文件
            SKIP_SIBLINGS　　继续访问，但是不再访问这个目录下的任何项了
            SKIP_SUBTREE 　继续访问，但是不再访问这个文件的兄弟文件（和该文件在同一目录下的文件）
            TERMINATE 　终止访问
            当有任何异常抛出时，就会终止访问，而这个异常就会从walkFileTree方法中抛出。

    */

public class _23_nio文件复制 {
    public static void main(String[] args) throws IOException {
        // nio 实现implements FileVisitor接口，实现实现目录的复制功能
        nioCopyTest1();
        nioCopyTest2();
        nioCopyTest3();
        /*控制台输出:
        nioCopyTest1耗费时间:1417
        nioCopyTest2耗费时间:142
        nioCopyTest3耗费时间:68*/

        Path source = Path.of("a.txt");
        Path target = Paths.get("b.txt");
        Files.copy(source, target, StandardCopyOption.REPLACE_EXISTING);
    }

    /**
     * 通道之间的数据传输(直接缓冲区的模式)
     */
    private static void nioCopyTest3() throws IOException {
        long startTime = System.currentTimeMillis();
        FileChannel inChannel = FileChannel.open(Paths.get("E:\\ 1.avi"), StandardOpenOption.READ);
        FileChannel outChennel = FileChannel.open(Paths.get("E:\\ 13.avi"), StandardOpenOption.WRITE, StandardOpenOption.READ, StandardOpenOption.CREATE_NEW);
        outChennel.transferFrom(inChannel, 0, inChannel.size());
        long end = System.currentTimeMillis();
        System.out.println("nioCopyTest3耗费时间:" + (end - startTime));
    }

    /**
     * 使用直接缓冲区完成文件的复制(内存映射文件)
     */
    private static void nioCopyTest2() throws IOException {
        long startTime = System.currentTimeMillis();
        FileChannel inChannel = FileChannel.open(Paths.get("E:\\ 1.avi"), StandardOpenOption.READ);
        FileChannel outChennel = FileChannel.open(Paths.get("E:\\ 12.avi"), StandardOpenOption.WRITE, StandardOpenOption.READ, StandardOpenOption.CREATE_NEW);

        //内存映射文件(什么模式 从哪开始 到哪结束)
        MappedByteBuffer inMappeBuf = inChannel.map(FileChannel.MapMode.READ_ONLY, 0, inChannel.size());
        MappedByteBuffer outMappeBuf = outChennel.map(FileChannel.MapMode.READ_WRITE, 0, inChannel.size());

        //直接都缓冲区进行数据的读写操作
        byte[] dst = new byte[inMappeBuf.limit()];
        inMappeBuf.get(dst);
        outMappeBuf.put(dst);

        inChannel.close();
        outChennel.close();
        long end = System.currentTimeMillis();
        System.out.println("nioCopyTest2耗费时间:" + (end - startTime));
    }


    /**
     * 非直接缓冲区 文件的复制
     *
     * @throws IOException
     */
    private static void nioCopyTest1() throws IOException {
        long startTime = System.currentTimeMillis();
        FileInputStream fileInputStream = new FileInputStream(new File("E:\\ 1.avi"));
        FileOutputStream fileOutputStream = new FileOutputStream("E:\\ 11.avi");

        //获取通道
        FileChannel inChannel = fileInputStream.getChannel();
        FileChannel outChanel = fileOutputStream.getChannel();

        //分配缓冲区的大小
        ByteBuffer buf = ByteBuffer.allocate(1024);

        //将通道中的数据存入缓冲区
        while (inChannel.read(buf) != -1) {
            buf.flip();//切换读取数据的模式
            outChanel.write(buf);
            buf.clear();
        }
        outChanel.close();
        inChannel.close();
        fileInputStream.close();
        fileOutputStream.close();
        long end = System.currentTimeMillis();
        System.out.println("nioCopyTest1耗费时间:" + (end - startTime));
    }
}
